From b2d0389357420def602ef744551d51dc041b710e Mon Sep 17 00:00:00 2001 From: robertl Date: Mon, 23 Nov 2009 06:36:17 +0000 Subject: [PATCH] =?utf8?q?Christian=20B=C3=BChler=20adds=20binary=20LMX=20?= =?utf8?q?support.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- lmx.c | 176 +++++++++++++++++--- reference/binary.lmx | Bin 0 -> 1407 bytes reference/nokia.lmx | 223 +++++++++++++------------- skytraq.c | 2 +- testo | 3 +- xmldoc/formats/lmx.xml | 16 +- xmldoc/formats/options/lmx-binary.xml | 9 ++ 7 files changed, 286 insertions(+), 143 deletions(-) create mode 100644 reference/binary.lmx create mode 100644 xmldoc/formats/options/lmx-binary.xml diff --git a/lmx.c b/lmx.c index f40762b78..84fd561ea 100644 --- a/lmx.c +++ b/lmx.c @@ -32,11 +32,15 @@ static gbfile *ofd; static waypoint *wpt_tmp; char *urllink, *urllinkt; +static char *binary = NULL; #define MYNAME "lmx" static arglist_t lmx_args[] = { + { "binary", &binary, + "Compact binary representation", + NULL, ARGTYPE_BOOL, ARG_NOMINMAX }, ARG_TERMINATOR }; @@ -57,61 +61,181 @@ lmx_wr_deinit(void) gbfclose(ofd); } +static char * +lmx_stag(int tag) +{ + switch (tag) { + case 0xC5: return "lmx"; + case 0x46: return "landmarkCollection"; + case 0x47: return "landmark"; + case 0x48: return "name"; + case 0x49: return "description"; + case 0x4A: return "coordinates"; + case 0x4B: return "latitude"; + case 0x4C: return "longitude"; + case 0x4D: return "altitude"; + case 0x4E: return "horizontalAccuracy"; + case 0x4F: return "verticalAccuracy"; + case 0x50: return "timeStamp"; + case 0x51: return "coverageRadius"; + case 0x52: return "category"; + case 0x53: return "id"; + case 0x54: return "addressInfo"; + case 0x55: return "country"; + case 0x56: return "countryCode"; + case 0x57: return "state"; + case 0x58: return "county"; + case 0x59: return "city"; + case 0x5A: return "district"; + case 0x5B: return "postalCode"; + case 0x5C: return "crossing1"; + case 0x5D: return "crossing2"; + case 0x5E: return "street"; + case 0x5F: return "buildingName"; + case 0x60: return "buildingFloor"; + case 0x61: return "buildingZone"; + case 0x62: return "buildingRoom"; + case 0x63: return "extension"; + case 0x64: return "phoneNumber"; + case 0x65: return "mediaLink"; + case 0x66: return "mime"; + case 0x67: return "url"; + default: return 0; + } +} + static void -lmx_write_xml(int indent_level, const char *tag, const char *data) +lmx_indent(int count) { int i; - char *tmp_ent = xml_entitize(data); + for (i=0; i", lmx_stag(tag)); } +} - gbfprintf(ofd, "<%s>%s\n", tag, tmp_ent, tag); +static void +lmx_end_tag(int tag, int indent) +{ + if (binary) + gbfputc(0x01, ofd); + else { + lmx_indent(indent); + gbfprintf(ofd, "\n", lmx_stag(tag)); + } +} - xfree(tmp_ent); +static void +lmx_write_xml(int tag, const char *data, int indent) +{ + lmx_start_tag(tag, indent); + + if (binary) { + gbfputc(0x03, ofd); // inline string follows + gbfputcstr(data, ofd); + } + else { + char *tmp_ent = xml_entitize(data); + gbfputs(tmp_ent, ofd); + xfree(tmp_ent); + } + + lmx_end_tag(tag, 0); } static void lmx_print(const waypoint *wpt) { - gbfprintf(ofd, " \n"); - if (wpt->shortname) { - lmx_write_xml(4, "lm:name", global_opts.synthesize_shortnames ? wpt->description : wpt->shortname); + const char *oname; + char *odesc; + char tbuf[100]; + + /* + * Desparation time, try very hard to get a good shortname + */ + odesc = wpt->notes; + if (!odesc) { + odesc = wpt->description; + } + if (!odesc) { + odesc = wpt->shortname; + } + + oname = global_opts.synthesize_shortnames ? odesc : wpt->shortname; + + lmx_start_tag(0x47, 2); // landmark + if (!binary) gbfputc('\n', ofd); + if (oname) { + lmx_write_xml(0x48, oname, 3); // name } if (wpt->description) { - lmx_write_xml(4, "lm:description", wpt->description); + lmx_write_xml(0x49, wpt->description, 3); // description } - gbfprintf(ofd, " \n"); - gbfprintf(ofd, " %f\n", wpt->latitude); - gbfprintf(ofd, " %f\n",wpt->longitude); + lmx_start_tag(0x4A, 3); // coordinates + if (!binary) gbfputc('\n', ofd); + + sprintf(tbuf, "%f", wpt->latitude); + lmx_write_xml(0x4B, tbuf, 4); // latitude + + sprintf(tbuf, "%f", wpt->longitude); + lmx_write_xml(0x4C, tbuf, 4); // longitude + if (wpt->altitude && (wpt->altitude != unknown_alt)) { - gbfprintf(ofd, " %f\n",wpt->altitude); + sprintf(tbuf, "%f", wpt->altitude); + lmx_write_xml(0x4D, tbuf, 4); // altitude } - gbfprintf(ofd, " \n"); + lmx_end_tag(0x4A, 3); // coordinates if (wpt->url && wpt->url[0]) { - gbfprintf(ofd, " \n"); + lmx_start_tag(0x65, 3); // mediaLink + if (!binary) gbfputc('\n', ofd); if (wpt->url_link_text) - lmx_write_xml(5,"lm:name", wpt->url_link_text); - lmx_write_xml(5, "lm:url", wpt->url); - gbfprintf(ofd, " \n"); + lmx_write_xml(0x48, wpt->url_link_text, 4); // name + lmx_write_xml(0x67, wpt->url, 4); // url + lmx_end_tag(0x65, 3); // mediaLink } - gbfprintf(ofd, " \n"); + lmx_end_tag(0x47, 2); // landmark } static void lmx_write(void) { - gbfprintf(ofd, "\n"); - gbfprintf(ofd, ""); + if (binary) { + gbfputc(0x03, ofd); // WBXML version 1.3 + gbfputuint16(0x04A4, ofd); // "-//NOKIA//DTD LANDMARKS 1.0//EN" + gbfputc(106, ofd); // Charset=UTF-8 + gbfputc(0x00, ofd); // empty string table + gbfputc(0xC5, ofd); // lmx + gbfputc(0x05, ofd); // xmlns=http://www.nokia.com/schemas/location/landmarks/ + gbfputc(0x85, ofd); // 1/0/ + gbfputc(0x06, ofd); // xmlns:xsi= + gbfputc(0x86, ofd); // http://www.w3.org/2001/XMLSchema-instance + gbfputc(0x07, ofd); // xsi:schemaLocation=http://www.nokia.com/schemas/location/landmarks/ + gbfputc(0x85, ofd); // 1/0/ + gbfputc(0x87, ofd); // whitespace + gbfputc(0x88, ofd); // lmx.xsd + gbfputc(0x01, ofd); // END lmx attributes + } else { + gbfprintf(ofd, "\n"); + gbfprintf(ofd, "\n"); + } - gbfprintf(ofd, " \n"); + lmx_start_tag(0x46, 1); // landmarkCollection + if (!binary) gbfputc('\n', ofd); waypt_disp_all(lmx_print); - gbfprintf(ofd, " \n"); - gbfprintf(ofd, "\n"); + lmx_end_tag(0x46, 1); // landmarkCollection + lmx_end_tag(0xC5, 0); // lmx } /* @@ -242,5 +366,5 @@ ff_vecs_t lmx_vecs = { lmx_write, NULL, lmx_args, - CET_CHARSET_ASCII, 0 /* CET-REVIEW */ + CET_CHARSET_UTF8, 0 /* CET-REVIEW */ }; diff --git a/reference/binary.lmx b/reference/binary.lmx new file mode 100644 index 0000000000000000000000000000000000000000..cceb86ee918db68478c624ed89bfd730a0c42058 GIT binary patch literal 1407 zcmb`H-Hww$6vrX>@fvfbSHgV23}a$UX-ms)jT>9zrJ1cGjHS>3-G&EP^+9}=nd zd8gCKO=Y>&*Q!X}ZMpYqDR-XvAU}WU|93@wc$>`L5XO)$XLo35LYQIO=(?M#%yR=I zP>2sIFB|Xz#A2`Vwnw8btA8)xzR^=AHI$n=*i68ZyKen>}U;?%#$!VK%S zB+jZ#MFCbS&6=z{*78husQ+mtLKt1>n2(t8H<~d7A<~x4F~gC`T;eQ5p>!Mj9P4JT z|A@ZM7xm!)io;-3Wyn1G5sE+_8>n^GzO2Dg_2G|IC1c}HR`Vh?b7-bgqlK(9)F&*2 zoSD1vd|}@={`;{ch)p_Qs%hGfhfBsh@JUpKR(K<-UH!-wu)yqyGaJWn)Qy2KrF6(P eGi*tb8%=uQ{1-38;Q)^^Y - - - GCEBB - Mountain Bike Heaven by susy1313 - - 35.972033 - -87.134700 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=3771 - - - - GC1A37 - The Troll by a182pilot & Family - - 36.090683 - -86.679550 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=6711 - - - - GC1C2B - Dive Bomber by JoGPS & family - - 35.996267 - -86.620117 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=7211 - - - - GC25A9 - FOSTER by JoGPS & Family - - 36.038483 - -86.648617 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=9641 - - - - GC2723 - Logan Lighthouse by JoGps & Family - - 36.112183 - -86.741767 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=10019 - - - - GC2B71 - Ganier Cache by Susy1313 - - 36.064083 - -86.790517 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=11121 - - - - GC309F - Shy's Hill by FireFighterEng33 - - 36.087767 - -86.809733 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=12447 - - - - GC317A - GittyUp by JoGPS / Warner Parks - - 36.057500 - -86.892000 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=12666 - - - - GC317D - Inlighting by JoGPS / Warner Parks - - 36.082800 - -86.867283 - - - Cache Details - http://www.geocaching.com/seek/cache_details.asp?ID=12669 - - - + + + + + GCEBB + Mountain Bike Heaven by susy1313 + + 35.972033 + -87.134700 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=3771 + + + + GC1A37 + The Troll by a182pilot & Family + + 36.090683 + -86.679550 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=6711 + + + + GC1C2B + Dive Bomber by JoGPS & family + + 35.996267 + -86.620117 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=7211 + + + + GC25A9 + FOSTER by JoGPS & Family + + 36.038483 + -86.648617 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=9641 + + + + GC2723 + Logan Lighthouse by JoGps & Family + + 36.112183 + -86.741767 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=10019 + + + + GC2B71 + Ganier Cache by Susy1313 + + 36.064083 + -86.790517 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=11121 + + + + GC309F + Shy's Hill by FireFighterEng33 + + 36.087767 + -86.809733 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=12447 + + + + GC317A + GittyUp by JoGPS / Warner Parks + + 36.057500 + -86.892000 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=12666 + + + + GC317D + Inlighting by JoGPS / Warner Parks + + 36.082800 + -86.867283 + + + Cache Details + http://www.geocaching.com/seek/cache_details.asp?ID=12669 + + + diff --git a/skytraq.c b/skytraq.c index c65221428..54d29d532 100644 --- a/skytraq.c +++ b/skytraq.c @@ -1192,7 +1192,7 @@ file_read(void) break; } } - free(buffer); + xfree(buffer); db(1, MYNAME ": Got %i trackpoints from %i sectors.\n", st.tpn, sectors_read); } diff --git a/testo b/testo index 2134fb858..34a4cad0e 100755 --- a/testo +++ b/testo @@ -1298,6 +1298,8 @@ compare ${REFERENCE}/umsonstdraussen.gpx ${TMPDIR}/umsonstdraussen.gpx # gpsbabel -i lmx -f ${REFERENCE}/nokia.lmx -o lmx -F ${TMPDIR}/nokia.lmx compare ${REFERENCE}/nokia.lmx ${TMPDIR}/nokia.lmx +gpsbabel -i lmx -f ${REFERENCE}/nokia.lmx -o lmx,binary -F ${TMPDIR}/binary.lmx +bincompare ${REFERENCE}/binary.lmx ${TMPDIR}/binary.lmx # # Swiss Map (.xol) tests @@ -1638,7 +1640,6 @@ compare ${TMPDIR}/vpl_reference.gpx ${REFERENCE}/track/vpl_reference.gpx rm -f ${TMPDIR}/skytraq.* gpsbabel -t -w -i skytraq-bin -f ${REFERENCE}/skytraq.bin -o gpx -F ${TMPDIR}/skytraq.gpx compare ${TMPDIR}/skytraq.gpx ${REFERENCE}/skytraq.gpx - # # Teletype tests # diff --git a/xmldoc/formats/lmx.xml b/xmldoc/formats/lmx.xml index 8f512a87b..f668be441 100644 --- a/xmldoc/formats/lmx.xml +++ b/xmldoc/formats/lmx.xml @@ -1,6 +1,14 @@ -This format supports Nokia Landmark Exchange (LMX) files used by several -Nokia phones. GPSBabel supports only the traditional XML format and -not the compressed binary format. +This format supports + +Nokia Landmark Exchange (LMX) files used by several Nokia phones. +GPSBabel supports the traditional XML format for reading and writing. The +compressed binary format (WBXML) can be written, but most current Nokia phones +do not support it (confirmed with N82 and N95). + + +With this format, landmarks can be imported into the landmark store of the +mobile phone. This landmark store is then used to display them on a map with +several applications. The most common ones are the pre-installed Ovi Maps (or +its predecessor Nokia Maps) and Google Maps Mobile. - diff --git a/xmldoc/formats/options/lmx-binary.xml b/xmldoc/formats/options/lmx-binary.xml new file mode 100644 index 000000000..dbf05fb15 --- /dev/null +++ b/xmldoc/formats/options/lmx-binary.xml @@ -0,0 +1,9 @@ + +This option specifies if you want to write the compressed binary format (WBXML) +instead of the XML format. However, most current Nokia phones do only support +the XML format (confirmed with N82 and N95). + + +This option has no effect when used for input, only reading the traditional XML +format is supported. + -- 2.30.2